package cn.tedu.mall.order.service.impl;

import cn.tedu.mall.common.exception.CoolSharkServiceException;
import cn.tedu.mall.common.pojo.domain.CsmallAuthenticationInfo;
import cn.tedu.mall.common.restful.JsonPage;
import cn.tedu.mall.common.restful.ResponseCode;
import cn.tedu.mall.order.mapper.OmsOrderItemMapper;
import cn.tedu.mall.order.mapper.OmsOrderMapper;
import cn.tedu.mall.order.service.IOmsCartService;
import cn.tedu.mall.order.service.IOmsOrderService;
import cn.tedu.mall.order.utils.IdGeneratorUtils;
import cn.tedu.mall.pojo.order.dto.OrderAddDTO;
import cn.tedu.mall.pojo.order.dto.OrderItemAddDTO;
import cn.tedu.mall.pojo.order.dto.OrderListTimeDTO;
import cn.tedu.mall.pojo.order.dto.OrderStateUpdateDTO;
import cn.tedu.mall.pojo.order.model.OmsCart;
import cn.tedu.mall.pojo.order.model.OmsOrder;
import cn.tedu.mall.pojo.order.model.OmsOrderItem;
import cn.tedu.mall.pojo.order.vo.OrderAddVO;
import cn.tedu.mall.pojo.order.vo.OrderDetailVO;
import cn.tedu.mall.pojo.order.vo.OrderListVO;
import cn.tedu.mall.product.service.order.IForOrderSkuService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.elasticsearch.client.ml.EvaluateDataFrameRequest;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@DubboService  //订单模块需要被秒杀模块调用
@Service
@Slf4j
public class OmsOrderServiceImpl implements IOmsOrderService {
    //减少商品库存
    @DubboReference
    private IForOrderSkuService dubboOrderSkuService;
    //删除购物车中的商品
    @Autowired
    private IOmsCartService omsCartService;
    //新增订单
    @Autowired
    private OmsOrderMapper omsOrderMapper;
    //新增订单项
    @Autowired
    private OmsOrderItemMapper omsOrderItemMapper;

    //新增订单
    @Override
    public OrderAddVO addOrder(OrderAddDTO orderAddDTO) {
        //第一部分：收集信息，准备数据，生成订单
        OmsOrder omsOrder = new OmsOrder();
        BeanUtils.copyProperties(orderAddDTO,omsOrder);
        //进行订单的收集和计算
        loadOrder(omsOrder);
        //进行订单项的收集
        List<OrderItemAddDTO> orderItemAddDTOS = orderAddDTO.getOrderItems();
        //判断订单项是否为null，直接抛出异常
        if(orderItemAddDTOS==null)
            throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,"订单必须包含订单项");
        //准备好List<OmsOrderItem>
        List<OmsOrderItem> omsOrderItems = new ArrayList<>();
        //遍历orderItemAddDTOS进行对象的转化
        for (OrderItemAddDTO orderItemAddDTO : orderItemAddDTOS) {
            OmsOrderItem omsOrderItem = new OmsOrderItem();
            BeanUtils.copyProperties(orderItemAddDTO,omsOrderItem);
            //进行订单项的校验
            loadOrderItem(omsOrderItem);
            //赋值订单id
            omsOrderItem.setOrderId(omsOrder.getId());
            //将omsOrderItem添加到对应的集合中
            omsOrderItems.add(omsOrderItem);
            //信息收集以及计算过程结束，进行第二部分：操作数据库
            //2.1 减少库存
            int rows = dubboOrderSkuService.reduceStockNum(omsOrderItem.getSkuId(), omsOrderItem.getQuantity());
            //判断rows是否为0
            if (rows==0)
                throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,"商品库存不足");
            //2.2 删除购物车的信息
            OmsCart omsCart = new OmsCart();
            omsCart.setUserId(omsOrder.getUserId());
            omsCart.setSkuId(omsOrderItem.getSkuId());
            omsCartService.removeUserCarts(omsCart);
        }
        //2.3 新增订单
        omsOrderMapper.insertOrder(omsOrder);
        //2.4 新增订单项
        omsOrderItemMapper.insertOrderItem(omsOrderItems);
        //返回信息
        OrderAddVO orderAddVO = new OrderAddVO();
        orderAddVO.setId(omsOrder.getId()); //订单id
        orderAddVO.setSn(omsOrder.getSn()); //订单编号
        orderAddVO.setCreateTime(omsOrder.getGmtCreate()); //订单创建时间
        orderAddVO.setPayAmount(omsOrder.getAmountOfActualPay()); //需要支付的金额
        //千万要记得返回！！！
        return orderAddVO;
    }

    private void loadOrderItem(OmsOrderItem omsOrderItem) {
        //判断订单项的id是否为null
        if(omsOrderItem.getId()==null){
            Long id = IdGeneratorUtils.getDistributeId("order_item");
            omsOrderItem.setId(id);
        }
        //判断skuId是否为null，直接抛出异常
        if(omsOrderItem.getSkuId()==null)
            throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,"订单商品中必须包含skuId");
    }

    //进行订单的收集和计算
    private void loadOrder(OmsOrder omsOrder) {
        //1.判断订单id是否为null
        if(omsOrder.getId()==null){
            //利用leaf生成分布式id
            Long id = IdGeneratorUtils.getDistributeId("order");
            omsOrder.setId(id);
        }
        //2.判断订单编号是否为null
        if(omsOrder.getSn()==null){
            //生成订单编号
            String sn = UUID.randomUUID().toString();
            omsOrder.setSn(sn);
        }
        //3.判断用户id是否为null
        if(omsOrder.getUserId()==null){
            //获取用户id
            Long userId = getUserId();
            omsOrder.setUserId(userId);
        }
        //4.订单状态为null，赋予默认值0，0是未支付
        if(omsOrder.getState()==null)
            omsOrder.setState(0);
        //5.订单刚生成时，创建时间和生成时间以及下订单的时间只有有一个为null，就设置成一样的
        if(omsOrder.getGmtOrder()==null || omsOrder.getGmtCreate()==null ||
          omsOrder.getGmtModified()==null){
            LocalDateTime now = LocalDateTime.now();
            omsOrder.setGmtOrder(now);
            omsOrder.setGmtCreate(now);
            omsOrder.setGmtModified(now);
        }
        //6.商品原价为null，直接抛出异常
        if(omsOrder.getAmountOfOriginalPrice()==null)
            throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,"商品必须要有原价");
        //7.运费为null，设置为0
        if(omsOrder.getAmountOfFreight()==null)
            omsOrder.setAmountOfFreight(new BigDecimal(0.0));
        //8.优惠价格为null，设置为0
        if(omsOrder.getAmountOfDiscount()==null)
            omsOrder.setAmountOfDiscount(new BigDecimal(0.0));
        //9.计算实际支付金额：原价+运费-优惠=实际支付金额
        BigDecimal amountOfOriginalPrice = omsOrder.getAmountOfOriginalPrice();
        BigDecimal amountOfFreight = omsOrder.getAmountOfFreight();
        BigDecimal amountOfDiscount = omsOrder.getAmountOfDiscount();
        BigDecimal amountOfActualPrice = amountOfOriginalPrice.add(amountOfFreight).subtract(amountOfDiscount);
        omsOrder.setAmountOfActualPay(amountOfActualPrice);
    }

    @Override
    public void updateOrderState(OrderStateUpdateDTO orderStateUpdateDTO) {
        OmsOrder omsOrder = new OmsOrder();
        BeanUtils.copyProperties(orderStateUpdateDTO,omsOrder);
        omsOrderMapper.updateOrderById(omsOrder);
    }

    @Override
    public JsonPage<OrderListVO> listOrdersBetweenTimes(OrderListTimeDTO orderListTimeDTO) {
        //校验startTime和endTime是否有值
        validaTimeAndConvertTime(orderListTimeDTO);
        //获取用户id
        Long userId = getUserId();
        orderListTimeDTO.setUserId(userId);
        //设置分页条件
        PageHelper.startPage(orderListTimeDTO.getPage(),orderListTimeDTO.getPageSize());
        //开始查询
        List<OrderListVO> orderListVOS = omsOrderMapper.selectOrdersByTimes(orderListTimeDTO);
        return JsonPage.restPage(new PageInfo<>(orderListVOS));
    }

    private void validaTimeAndConvertTime(OrderListTimeDTO orderListTimeDTO) {
        //检验时间是否存在，如果存在就检查时间是否合理
        LocalDateTime startTime = orderListTimeDTO.getStartTime();
        LocalDateTime endTime = orderListTimeDTO.getEndTime();
        //判断起始时间和结束时间是否为null
        if(startTime==null || endTime==null){
            startTime = LocalDateTime.now().minusMonths(1);
            endTime = LocalDateTime.now();
            orderListTimeDTO.setStartTime(startTime);
            orderListTimeDTO.setEndTime(endTime);
        }else{
            //检查时间是否合理，开始时间要小于结束时间
            if(endTime.toInstant(ZoneOffset.of("+8")).toEpochMilli() <
            startTime.toInstant(ZoneOffset.of("+8")).toEpochMilli())
                throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,"结束时间应该大于开始时间");
        }
    }

    @Override
    public OrderDetailVO getOrderDetail(Long id) {
        OrderDetailVO orderDetailVO = omsOrderMapper.selectOrderById(id);
        return orderDetailVO;
    }
    //获取用户信息
    public CsmallAuthenticationInfo getUserInfo(){
        //通过Security请求上下文对象获取的token
        UsernamePasswordAuthenticationToken token =
                (UsernamePasswordAuthenticationToken)
                        SecurityContextHolder.getContext().getAuthentication();
        //判断token是否为空
        if(token==null)
            throw new CoolSharkServiceException(ResponseCode.UNAUTHORIZED,"没有登录信息");
        //从token中获取用户信息
        CsmallAuthenticationInfo userInfo = (CsmallAuthenticationInfo) token.getCredentials();
        return userInfo;
    }
    //获取userId
    public Long getUserId(){
        return getUserInfo().getId();
    }
}
